Working with Lists in Dart
Lists are one of the most commonly used collection types in Dart. A List stores multiple values in an ordered sequence, and each value can be accessed using an index. Lists are especially important in Flutter because they are frequently used to manage UI data such as products, users, messages, categories, menu items, and API responses.
In Dart, a list is an indexable collection of objects. List indexes start from 0, so the first element is at index 0 and the last element is at length - 1.
1. What is a List?
A List is an ordered collection of values. Unlike a Set, a List preserves the order of its elements and allows duplicate values.
List fruits = ['Apple', 'Banana', 'Mango'];
print(fruits);
Output:
[Apple, Banana, Mango]
Important Characteristics
- Lists are ordered collections.
- List indexing starts from 0.
- Lists can contain duplicate values.
- Lists can be growable or fixed-length.
- Lists can be strongly typed using generics.
- Lists provide many useful methods for adding, removing, searching, sorting, and transforming data.
2. Creating a List
Using a List Literal
var numbers = [10, 20, 30, 40, 50];
Dart can infer the list type from its values, so the above list is inferred as List.
Creating an Explicitly Typed List
List names = ['Amit', 'Rahul', 'Neha'];
List marks = [80, 75, 92];
List prices = [99.99, 149.50, 299.00];
Creating an Empty List
List students = [];
students.add('Rahul');
students.add('Priya');
print(students);
Using Generic Type Syntax
var cities = ['Mumbai', 'Delhi', 'Pune'];
3. Accessing List Elements
Use square brackets [] with an index to access an element.
List fruits = ['Apple', 'Banana', 'Mango'];
print(fruits[0]);
print(fruits[1]);
print(fruits[2]);
Output:
Apple
Banana
Mango
Index Positions
| Index | Value |
| 0 | Apple |
| 1 | Banana |
| 2 | Mango |
4. Getting the Length of a List
The length property returns the number of elements in a list.
var numbers = [10, 20, 30, 40];
print(numbers.length);
Output:
4
5. Updating List Elements
List elements can be changed using their indexes.
var fruits = ['Apple', 'Banana', 'Mango'];
fruits[1] = 'Orange';
print(fruits);
Output:
[Apple, Orange, Mango]
6. Checking Whether a List is Empty
Dart provides isEmpty and isNotEmpty properties.
var items = [];
print(items.isEmpty);
print(items.isNotEmpty);
Output:
true
false
7. Adding Elements to a List
Using add()
The add() method adds one element to the end of a growable list.
var fruits = ['Apple', 'Banana'];
fruits.add('Mango');
print(fruits);
Output:
[Apple, Banana, Mango]
Using addAll()
The addAll() method adds multiple elements.
var fruits = ['Apple', 'Banana'];
fruits.addAll(['Mango', 'Orange', 'Grapes']);
print(fruits);
Output:
[Apple, Banana, Mango, Orange, Grapes]
8. Inserting Elements
Using insert()
The insert() method adds an element at a specific index.
var fruits = ['Apple', 'Mango'];
fruits.insert(1, 'Banana');
print(fruits);
Output:
[Apple, Banana, Mango]
Using insertAll()
var numbers = [10, 50];
numbers.insertAll(1, [20, 30, 40]);
print(numbers);
Output:
[10, 20, 30, 40, 50]
9. Removing Elements
remove()
Removes the first matching element.
var fruits = ['Apple', 'Banana', 'Mango'];
fruits.remove('Banana');
print(fruits);
removeAt()
Removes an element at a specific index.
var fruits = ['Apple', 'Banana', 'Mango'];
fruits.removeAt(1);
print(fruits);
Output:
[Apple, Mango]
removeLast()
var numbers = [10, 20, 30];
numbers.removeLast();
print(numbers);
removeRange()
var numbers = [10, 20, 30, 40, 50];
numbers.removeRange(1, 4);
print(numbers);
Output:
[10, 50]
clear()
The clear() method removes all elements.
var fruits = ['Apple', 'Banana', 'Mango'];
fruits.clear();
print(fruits);
Output:
[]
10. Searching in a List
contains()
var fruits = ['Apple', 'Banana', 'Mango'];
print(fruits.contains('Banana'));
print(fruits.contains('Orange'));
Output:
true
false
indexOf()
The indexOf() method returns the index of the first matching element.
var fruits = ['Apple', 'Banana', 'Mango'];
print(fruits.indexOf('Mango'));
Output:
2
lastIndexOf()
var numbers = [10, 20, 10, 30];
print(numbers.lastIndexOf(10));
Output:
2
11. Iterating Through a List
Using for Loop
var fruits = ['Apple', 'Banana', 'Mango'];
for (int i = 0; i < fruits.length; i++) {
print(fruits[i]);
}
Using for-in Loop
var fruits = ['Apple', 'Banana', 'Mango'];
for (var fruit in fruits) {
print(fruit);
}
Using forEach()
var fruits = ['Apple', 'Banana', 'Mango'];
fruits.forEach((fruit) {
print(fruit);
});
12. first and last
You can directly access the first and last elements using first and last.
var numbers = [10, 20, 30, 40];
print(numbers.first);
print(numbers.last);
Output:
10
40
13. Sorting a List
Sorting Numbers
var numbers = [50, 10, 40, 20, 30];
numbers.sort();
print(numbers);
Output:
[10, 20, 30, 40, 50]
Sorting in Descending Order
var numbers = [50, 10, 40, 20, 30];
numbers.sort((a, b) => b.compareTo(a));
print(numbers);
Sorting Strings
var names = ['Rahul', 'Amit', 'Zoya', 'Neha'];
names.sort();
print(names);
14. Reversing a List
The reversed property returns the elements in reverse order as an Iterable.
var numbers = [10, 20, 30, 40];
var reversedNumbers = numbers.reversed.toList();
print(reversedNumbers);
Output:
[40, 30, 20, 10]
15. Filtering List Data with where()
The where() method returns elements that satisfy a condition.
var numbers = [10, 15, 20, 25, 30];
var evenNumbers = numbers.where((number) => number % 2 == 0).toList();
print(evenNumbers);
Output:
[10, 20, 30]
Practical Example
var marks = [45, 80, 32, 90, 65];
var passedStudents = marks.where((mark) => mark >= 40).toList();
print(passedStudents);
16. Transforming Lists with map()
The map() method transforms every element into another value.
var numbers = [1, 2, 3, 4, 5];
var squares = numbers.map((number) => number * number).toList();
print(squares);
Output:
[1, 4, 9, 16, 25]
Example with Strings
var names = ['amit', 'rahul', 'neha'];
var upperNames = names.map((name) => name.toUpperCase()).toList();
print(upperNames);
17. any() Method
The any() method checks whether at least one element satisfies a condition.
var numbers = [10, 20, 35, 40];
bool result = numbers.any((number) => number > 30);
print(result);
Output:
true
18. every() Method
The every() method checks whether all elements satisfy a condition.
var marks = [60, 70, 80, 90];
bool result = marks.every((mark) => mark >= 40);
print(result);
Output:
true
19. firstWhere()
firstWhere() returns the first element that satisfies a condition.
var numbers = [10, 15, 22, 35, 40];
var result = numbers.firstWhere((number) => number % 2 == 0);
print(result);
Output:
22
20. take() and skip()
take()
take() returns the first specified number of elements.
var numbers = [10, 20, 30, 40, 50];
var result = numbers.take(3).toList();
print(result);
Output:
[10, 20, 30]
skip()
var numbers = [10, 20, 30, 40, 50];
var result = numbers.skip(2).toList();
print(result);
Output:
[30, 40, 50]
21. sublist()
The sublist() method returns part of a list.
var numbers = [10, 20, 30, 40, 50];
var result = numbers.sublist(1, 4);
print(result);
Output:
[20, 30, 40]
The start index is included, while the end index is excluded.
22. List of Objects
Lists become especially useful when working with custom classes.
class Student {
String name;
int marks;
Student(this.name, this.marks);
}
void main() {
List students = [
Student('Amit', 85),
Student('Neha', 92),
Student('Rahul', 74),
];
for (var student in students) {
print('${student.name}: ${student.marks}');
}
}
This approach is commonly used in Flutter applications when displaying structured data.
23. Filtering a List of Objects
class Student {
String name;
int marks;
Student(this.name, this.marks);
}
void main() {
List students = [
Student('Amit', 85),
Student('Neha', 35),
Student('Rahul', 74),
];
var passed = students
.where((student) => student.marks >= 40)
.toList();
for (var student in passed) {
print(student.name);
}
}
24. List of Maps
Lists can also contain Map objects. This is common when handling JSON-like data.
List
25. Nested Lists
A list can contain other lists.
List> matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
print(matrix[0][1]);
print(matrix[2][2]);
Output:
2
9
26. List.generate()
List.generate() creates a list by calling a function for each index.
var numbers = List.generate(
5,
(index) => index + 1,
);
print(numbers);
Output:
[1, 2, 3, 4, 5]
Flutter Example
final colors = List.generate(
10,
(index) => 'Color $index',
);
27. List.filled()
List.filled() creates a list with a specified number of elements.
var numbers = List.filled(5, 0);
print(numbers);
Output:
[0, 0, 0, 0, 0]
28. Fixed-Length and Growable Lists
Growable List
A normal list literal creates a growable list.
var numbers = [10, 20, 30];
numbers.add(40);
print(numbers);
Fixed-Length List
var numbers = List.filled(3, 0);
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;
print(numbers);
A fixed-length list does not allow operations that change its length, such as add() or remove().
29. final List vs const List
final List
final prevents the variable from referring to a different list, but the contents of a normal growable list can still be changed.
final fruits = ['Apple', 'Banana'];
fruits.add('Mango');
print(fruits);
const List
A const list is compile-time constant and cannot be modified.
const fruits = ['Apple', 'Banana'];
// fruits.add('Mango'); // Error
30. Spread Operator
The spread operator ... inserts elements from another collection into a list.
var first = [1, 2, 3];
var second = [4, 5, 6];
var combined = [...first, ...second];
print(combined);
Output:
[1, 2, 3, 4, 5, 6]
31. Null-Aware Spread Operator
The ...? operator allows a nullable list to be spread without causing an error when the list is null.
List? extraItems;
var items = [
'Apple',
...?extraItems,
'Mango'
];
print(items);
32. Collection-if
Dart allows conditional elements inside collection literals.
bool isAdmin = true;
var menuItems = [
'Home',
'Profile',
if (isAdmin) 'Admin Panel',
];
print(menuItems);
Output:
[Home, Profile, Admin Panel]
33. Collection-for
A for loop can also be used inside a collection literal.
var numbers = [
for (var i = 1; i <= 5; i++) i * 10
];
print(numbers);
Output:
[10, 20, 30, 40, 50]
34. Combining Collection-if and Collection-for
bool includeEven = true;
var numbers = [
for (var i = 1; i <= 10; i++)
if (!includeEven || i % 2 == 0) i
];
print(numbers);
35. Calculating Values from a List
Using reduce()
var numbers = [10, 20, 30, 40];
var total = numbers.reduce((a, b) => a + b);
print(total);
Output:
100
Using fold()
var numbers = [10, 20, 30, 40];
var total = numbers.fold(0, (sum, number) => sum + number);
print(total);
36. Joining List Elements
The join() method combines list elements into a string.
var names = ['Amit', 'Rahul', 'Neha'];
var result = names.join(', ');
print(result);
Output:
Amit, Rahul, Neha
37. Copying a List
You can create a separate list using List.from() or List.of().
var original = [10, 20, 30];
var copy = List.from(original);
copy.add(40);
print(original);
print(copy);
Output:
[10, 20, 30]
[10, 20, 30, 40]
38. Practical Shopping Cart Example
class Product {
String name;
double price;
Product(this.name, this.price);
}
void main() {
List cart = [
Product('Laptop', 55000),
Product('Mouse', 1200),
Product('Keyboard', 2500),
];
double total = cart.fold(
0,
(sum, product) => sum + product.price,
);
print('Cart Items:');
for (var product in cart) {
print('${product.name} - ₹${product.price}');
}
print('Total: ₹$total');
}
39. Working with Lists in Flutter
Lists are frequently used in Flutter to generate widgets dynamically. Instead of manually writing every widget, you can store data in a list and generate widgets from that data.
Example: Dynamic Text Widgets
import 'package:flutter/material.dart';
class FruitList extends StatelessWidget {
FruitList({super.key});
final List fruits = [
'Apple',
'Banana',
'Mango',
'Orange',
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Fruits'),
),
body: ListView.builder(
itemCount: fruits.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(fruits[index]),
);
},
),
);
}
}
40. Updating a List in Flutter
When list data changes inside a StatefulWidget, setState() can be used to rebuild the UI.
class TodoPage extends StatefulWidget {
const TodoPage({super.key});
@override
State createState() => _TodoPageState();
}
class _TodoPageState extends State {
final List todos = [];
void addTodo() {
setState(() {
todos.add('New Task');
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Todo List'),
),
body: ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(todos[index]),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: addTodo,
child: const Icon(Icons.add),
),
);
}
}
41. List of Products in Flutter
final products = [
{
'name': 'Laptop',
'price': 55000,
},
{
'name': 'Phone',
'price': 25000,
},
{
'name': 'Headphones',
'price': 3000,
},
];
The data can then be displayed dynamically:
ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
final product = products[index];
return ListTile(
title: Text(product['name'].toString()),
subtitle: Text('₹${product['price']}'),
);
},
)
42. Common List Methods
| Method/Property | Purpose |
| length | Returns the number of elements. |
| isEmpty | Checks whether the list is empty. |
| isNotEmpty | Checks whether the list contains elements. |
| add() | Adds one element. |
| addAll() | Adds multiple elements. |
| insert() | Inserts an element at an index. |
| insertAll() | Inserts multiple elements. |
| remove() | Removes a matching element. |
| removeAt() | Removes an element at an index. |
| removeLast() | Removes the last element. |
| removeRange() | Removes a range of elements. |
| clear() | Removes all elements. |
| contains() | Checks whether an element exists. |
| indexOf() | Finds the first matching index. |
| sort() | Sorts the list. |
| where() | Filters elements. |
| map() | Transforms elements. |
| any() | Checks whether at least one element matches. |
| every() | Checks whether all elements match. |
| firstWhere() | Finds the first matching element. |
| take() | Gets the first specified number of elements. |
| skip() | Skips the first specified number of elements. |
| sublist() | Gets a portion of the list. |
| join() | Combines elements into a string. |
| fold() | Combines elements into a single result. |
43. List vs Set vs Map
| Collection | Structure | Duplicates | Access |
| List | Ordered values | Allowed | Index |
| Set | Unique values | Not allowed | By value |
| Map | Key-value pairs | Keys must be unique | By key |
44. Common Mistakes
- Trying to access an index that does not exist.
- Calling
remove() or add() on a fixed-length list.
- Forgetting to call
toList() when a real List is required from an Iterable result such as map(), where(), or reversed.
- Using
dynamic unnecessarily instead of specifying a useful list type.
- Modifying a list while iterating over it without understanding the consequences.
- Using a very large static list directly in a Flutter UI instead of an appropriate lazy builder such as
ListView.builder.
- Accessing
first or last on an empty list.
45. Best Practices
- Use generic types such as
List and List whenever possible.
- Use meaningful variable names such as
students, products, and cartItems.
- Use
where() for filtering and map() for transformation.
- Use
ListView.builder for large or dynamically generated Flutter lists.
- Check
isNotEmpty before accessing first or last when the list may be empty.
- Use immutable or unmodifiable collections where mutation is not required.
- Prefer strongly typed model classes for complex application data instead of deeply nested
Map structures.
- Use collection-if, collection-for, and spread operators to build collections cleanly.
46. Mini Project: Student Marks Management
class Student {
String name;
int marks;
Student(this.name, this.marks);
}
void main() {
List students = [
Student('Amit', 85),
Student('Rahul', 35),
Student('Neha', 92),
Student('Priya', 68),
];
print('All Students:');
for (var student in students) {
print('${student.name}: ${student.marks}');
}
var passedStudents = students
.where((student) => student.marks >= 40)
.toList();
print('\nPassed Students:');
for (var student in passedStudents) {
print(student.name);
}
var marks = students.map((student) => student.marks).toList();
var totalMarks = marks.fold(
0,
(sum, mark) => sum + mark,
);
var average = totalMarks / marks.length;
print('\nAverage Marks: $average');
}
47. Practice Exercises
- Create a list of 10 integers and print all elements.
- Find the largest number in a list.
- Find the smallest number in a list.
- Filter all even numbers from a list.
- Filter all numbers greater than 50.
- Sort a list in ascending and descending order.
- Remove duplicate values from a collection using a Set and convert it back to a List.
- Create a list of student objects and display students who scored more than 75.
- Create a shopping cart using a list of Product objects and calculate the total price.
- Display a list of products dynamically using Flutter's
ListView.builder.
48. Quick Revision
- List: Ordered collection of values.
- Index: Position of an element, starting from 0.
- length: Number of elements.
- add(): Adds one element.
- addAll(): Adds multiple elements.
- remove(): Removes a matching element.
- removeAt(): Removes an element by index.
- where(): Filters elements.
- map(): Transforms elements.
- sort(): Sorts elements.
- contains(): Checks whether an element exists.
- for-in: Iterates through elements.
- List.generate(): Generates a list programmatically.
- ...: Spread operator.
- ...?: Null-aware spread operator.
- ListView.builder: Efficiently builds dynamic Flutter list UIs.
49. Conclusion
Working with Lists is an essential Dart skill for Flutter development. Lists allow developers to store, access, update, filter, sort, transform, and display collections of data efficiently. Once you understand list operations such as add(), remove(), where(), map(), sort(), collection operators, and list iteration, you can build dynamic Flutter interfaces that work with real application data.
Official Dart Resources
Learn Flutter with JustAcademy